home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / PASROTO.ZIP / ROTO.ASM < prev    next >
Assembly Source File  |  1996-05-23  |  13KB  |  479 lines

  1. comment #/*
  2.  
  3. cache optimized roto-zoomer (c) '95/96 Niklas Beisert / pascal
  4.  
  5. Use this in your non commercial productions if you are too lazy,
  6. or use some of the ideas in this "article" if you like, but don't be too
  7. lazy to greet me then! ;)
  8. Spread it only with all associated files:
  9.   FILE_ID.DIZ
  10.   ROTO.ASM
  11.   ROTO.H
  12.   ROTO.OBJ
  13.   MAKEFILE
  14.   ROTOEXAM.CPP
  15.   ROTO.EXE
  16.   TIMER.ASM
  17.   TIMER.H
  18.  
  19. Send me some money: :)
  20.   pascal@nightmare.harz.de, Niklas Beisert@2:2437/301.44
  21.   Niklas Beisert, Oberstrasse 84, 20149 Hamburg, Germany
  22.  
  23. Thanks go to jmagic/complex for releasing some source of his asm94 intro.
  24. The texture innerloop is quite fast and pentium optimized, so I used it! ;)
  25. Furthermore thanks go to Daredevil and Tran for pmode/w (lite).
  26.  
  27.  
  28.  usage: texturescreen dst,src,x0,y0,xx,xy,yx,yy,xblk,yblk,scrwid,op,dir
  29.                  dst: destination address. eg:0xA0000
  30.                  src: segment aligned (0xijkl0000) 256x256 map
  31.    x0,y0,xx,xy,yx,yy: 16:16 fixpoint transformation matrix
  32.            xblk,yblk: a block is 8x8, so 320x200 would be 40,25
  33.               scrwid: bytes per line
  34.                   op: opcode: 0x89:mov, 0x01:add...
  35.                  dir: blockorder: 0:horizontal first, 1:vertical first
  36.  
  37.  tested and compiled with watcom c++ 10.0 and tasm 3.1
  38.  
  39.  
  40.  transformation: dst[x,y]=src[x0+xx*x+xy*y,y0+yx*x+yy*y]
  41.  
  42.  history and background:
  43.    Second Reality: you remeber the head with the pentagram and the
  44.    lens effect... then a flash and whooopsy, what's that? this is 160x100...
  45.    Why? Otherwise it'd be too slow! But why, This is such a simple effect?
  46.    When I (some time later) recoded this effect I noticed that the framerate
  47.    drops at a certain angle, and the only reason could be the cache.
  48.    The processor cache is organized in a special way to have fast access
  49.    to it's memory. So you have cache lines of 16 (32) bytes on a 486 (pentium)
  50.    which are atoms. They all have a tag address field which stores the
  51.    position of the 16 (32) bytes in memory. Then you have 4 (2) ways which
  52.    are in a way 4 (2) equal caches which can be processed at the same time.
  53.    Finally there are 256 sets of one cache line per way. Bits 4-11 (5-12) of
  54.    the address determine the used set for a memory access.
  55.    At a memory access, the address is split into 3 parts: bits 0-3 (0-4)
  56.    determine the byte in a line, bits 4-11 (5-12) determine the set, and
  57.    bits 12-31 (13-31) are the tag address. The tag address is then compared
  58.    to the tag addresses of the 4 (2) lines of the set. If one matches it is
  59.    a cache hit, if not you get a cache miss, 16 (32) bytes are read from
  60.    memory to the least recently used cache line of that set. This takes
  61.    about 23 cycles on a 486dx2-66, while a cache hit takes no extra cycles.
  62.    A cache is most effective if you read the memory in a linear order like
  63.    you do it in a rotozoomer at low angles. You then get one cache miss
  64.    out of 16 (32) memory accesses. Now imagine the angle is exactly 90°.
  65.    You would then read then memory in steps of 256, after 8k the first
  66.    cache line is overwritten, so if you process the next line, it is a
  67.    cache miss. This results in 100% cache misses...
  68.    How to optimize it?
  69.    I had several discussions with Scholar / $eeN on this topic. (hiho!)
  70.    We though about rendering the screen in a different order, so that
  71.    the texture is read in a linear fashion. This would be diagonal lines
  72.    instead of h-lines. But this is not a fast solution either, and more
  73.    complicated anyway. You could also keep prerotated versions of the
  74.    texture, but this would require 2x or more the amount of memory,
  75.    and you are limited to a fixed texture if you do not want to modify
  76.    2 textures all the time.
  77.    The 8x8 block approach was a good compromise. :) You can write dwords,
  78.    and do not need too much memory while the cache contents are not
  79.    destroyed.
  80.    You can also use this 8x8 block approach to optimize movelist-tunnels:
  81.    keep the movelist linear, while you go though the 8x8 blocks.
  82.    And you can do other nice things with 8x8 blocks... ;))))))))))
  83.    Which I cannot tell you yet. probably later! =}
  84.    Cache optimizing seems to be quite stupid for vector engines, but
  85.    it is ESSENTIAL for fast bitmap effects.
  86.  
  87.    This little assembler fragments show you what cache can do and
  88.    what it cannot:
  89.  
  90.     fastloop:
  91.       mov dx,12
  92.     l1:
  93.         mov cx,32768
  94.       l2:
  95.           mov ax,[0]
  96.           mov ax,[0]
  97.           mov ax,[0]
  98.           mov ax,[0]
  99.           mov ax,[0]
  100.         dec cx
  101.         jnz l2
  102.       dec dx
  103.       jnz l1
  104.  
  105.     slowloop:
  106.       mov dx,12
  107.     l3:
  108.          mov cx,32768
  109.        l4:
  110.            mov ax,[2047]
  111.            mov ax,[4095]
  112.            mov ax,[6143]
  113.            mov ax,[8191]
  114.            mov ax,[10239]
  115.          dec cx
  116.          jnz l4
  117.        dec dx
  118.        jnz l3
  119.  
  120.    On a 486dx2-66 the first loop is about 25-50 times as fast as the second
  121.    one. If you don't believe me, try it yourself.
  122.    On a pentium 3 moves are enough to show the effects of the cache:
  123.            mov ax,[4095]
  124.            mov ax,[8191]
  125.            mov ax,[12287]
  126.    use those in the loop.
  127.  
  128.  
  129.  description:
  130.    This rotozoomer (also stretcher if you like...) does not process the
  131.    picture like it is usually done, line by line, but block by block.
  132.    The reason is simple: If you do it line by line you get 100% cache misses
  133.    beyond a certain rotation angle (~60° on a 486dx 8k processor cache).
  134.    100% cache misses mean 64000 (mode 13h) times 23 cycles on a
  135.    486dx2-66 (experimental value), which is > 20ms, and your frame rate
  136.    cannot get any better than 50Hz (ignoring all other operations).
  137.    You might end up at 30Hz at certain angels and 100Hz at others.
  138.    If you do it block by block you can reduce the cache misses to about
  139.    4000 to 8000 (2-5 ms), which has only little effect on the framerate.
  140.    You end up with a rotozoomer which runs at constant 100fps on a dx2-66.
  141.    or constant 350fps on a p120.
  142.  
  143.    Every 8x8 block is processed in the usual way, ie. 8 pixels, next line,
  144.    8 pixels, next line... The blocks are then drawn either in horizontal or
  145.    vertical order, ie. row by row vs column by column. If used correctly this
  146.    feature reduces the number of cache misses still a bit. You should use
  147.    vertical order, if the angle is about 90° or 270°. If it is rather 0° or
  148.    180° use horizontal order.
  149.  
  150.    I had no problem to use 4 rotozoomers at the same time in our intro
  151.    "LASSE REINB0NG" which was still quite smooth on a 486dx2-66 (>15fps).
  152.    This is the same routine as used in the intro, so believe me, it's fast.
  153.    (only that you can now control the blockorder)
  154.    Nothing was slowed down!
  155.  
  156.    On a P120 this routine nearly runs in 1 frame / retrace... (did I say
  157.    640x480??? :) )
  158.    That is why there is the bytes/line parameter. You can use this routine
  159.    with segmented screen memory. In 640x480 you should set the virtual screen
  160.    width to 1024. Then the bytes/line is not equal to yblocks*8. You can then
  161.    process a 80x8 blocks (640x64) range with this routine without segment
  162.    changes. If you process 7.5 of these ranges with segment changes in
  163.    between you can fill the screen with this routine.
  164. */#
  165.  
  166.  
  167. .486
  168. model flat,prolog
  169. locals
  170.  
  171. .code
  172.  
  173. adc_ecx macro lab
  174.   db 081h,0D1h
  175.     lab dd 0
  176. endm
  177.  
  178. adc_edx macro lab
  179.   db 081h,0D2h
  180.     lab dd 0
  181. endm
  182.  
  183. add_edx macro lab
  184.   db 081h,0C2h
  185.     lab dd 0
  186. endm
  187.  
  188. add_ecx macro lab
  189.   db 081h,0C1h
  190.     lab dd 0
  191. endm
  192.  
  193. sub_ecx macro lab
  194.   db 081h,0E9h
  195.     lab dd 0
  196. endm
  197.  
  198. add_edi macro lab
  199.   db 081h,0C7h
  200.     lab dd 0
  201. endm
  202.  
  203. textureblock proc
  204.   add_ecx beforedfy0
  205.   mov bh,dl
  206.   adc dl,0
  207.   mov bl,cl
  208.  
  209. @@block:
  210.     add_edx dfx0dy0_0
  211.     mov al,[ebx]
  212.     adc_ecx dfy0dx0_0
  213.     mov bh,dl
  214.     mov bl,cl
  215.     adc_edx dfx0dy0_1
  216.     mov ah,[ebx]
  217.     adc_ecx dfy0dx0_1
  218.     mov bh,dl
  219.     bswap eax
  220.     mov bl,cl
  221.  
  222.     adc_edx dfx0dy0_2
  223.     mov ah,[ebx]
  224.     adc_ecx dfy0dx0_2
  225.     mov bh,dl
  226.     mov bl,cl
  227.     adc_edx dfx0dy0_3
  228.     mov al,[ebx]
  229.     adc_ecx dfy0dx0_3
  230.     mov bh,dl
  231.     bswap eax
  232.     adc dl,0
  233.     op0 db 089h,007h ;//op [edi],eax
  234.     mov bl,cl
  235.  
  236.     add_edx dfx0dy0_4
  237.     mov al,[ebx]
  238.     adc_ecx dfy0dx0_4
  239.     mov bh,dl
  240.     mov bl,cl
  241.     adc_edx dfx0dy0_5
  242.     mov ah,[ebx]
  243.     adc_ecx dfy0dx0_5
  244.     mov bh,dl
  245.     bswap eax
  246.     mov bl,cl
  247.  
  248.     adc_edx dfx0dy0_6
  249.     mov ah,[ebx]
  250.     adc_ecx dfy7dx0
  251.     mov bh,dl
  252.     mov bl,cl
  253.     adc_edx dfx7dy7
  254.     mov al,[ebx]
  255.     adc_ecx dfy0dx7
  256.     mov bh,dl
  257.     bswap eax
  258.     adc dl,0
  259.     op1 db 089h,047h,004h ;//op [edi+4],eax
  260.     mov bl,cl
  261.  
  262.     add_edi scrwidth
  263.   dec esi
  264.   jnz @@block
  265.  
  266.   sub_ecx afterdfy0
  267.   sbb dl,0
  268.  
  269.   ret
  270. endp
  271.  
  272. public texturescreen_
  273.  
  274. texturescreen_ proc dst:dword, src:dword, x0:dword, y0:dword, xx:dword, xy:dword, yx:dword, yy:dword, xblocks:dword, yblocks:dword, scrwid:dword, op:dword, dir:dword
  275. local c1:dword, c2:dword, retxf1:dword, retyf1:dword, retsp1:dword, retxf2:dword, retyf2:dword, retsp2:dword, retxi1:byte, retyi1:byte, retxi2:byte, retyi2:byte
  276.   lea edi,textureblock+128
  277.  
  278.   mov eax,scrwid
  279.   mov [edi-128+scrwidth-textureblock],eax
  280.  
  281.   mov al,byte ptr op
  282.   mov [edi-128+op0-textureblock],al
  283.   mov [edi-128+op1-textureblock],al
  284.  
  285.   mov eax,xx
  286.   shl eax,16
  287.   mov al,byte ptr xy+2
  288.   mov [edi-128+dfx0dy0_0-textureblock],eax
  289.   mov [edi-128+dfx0dy0_1-textureblock],eax
  290.   mov [edi-128+dfx0dy0_2-textureblock],eax
  291.   mov [edi-128+dfx0dy0_3-textureblock],eax
  292.   mov [edi-128+dfx0dy0_4-textureblock],eax
  293.   mov [edi-128+dfx0dy0_5-textureblock],eax
  294.   mov [edi-128+dfx0dy0_6-textureblock],eax
  295.   mov ebx,xy
  296.   shl ebx,3
  297.   sub ebx,xy
  298.   neg ebx
  299.   add ebx,yy
  300.   shr ebx,16
  301.   mov al,bl
  302.   mov ebx,xx
  303.   shl ebx,19
  304.   sub eax,ebx
  305.   mov ebx,yx
  306.   shl ebx,16
  307.   add eax,ebx
  308.   mov [edi-128+dfx7dy7-textureblock],eax
  309.  
  310.   mov eax,xy
  311.   shl eax,16
  312.   mov [edi-128+beforedfy0-textureblock],eax
  313.   mov [edi-128+afterdfy0-textureblock],eax
  314.   mov al,byte ptr xx+2
  315.   mov [edi-128+dfy0dx0_0-textureblock],eax
  316.   mov [edi-128+dfy0dx0_1-textureblock],eax
  317.   mov [edi-128+dfy0dx0_2-textureblock],eax
  318.   mov [edi-128+dfy0dx0_3-textureblock],eax
  319.   mov [edi-128+dfy0dx0_4-textureblock],eax
  320.   mov [edi-128+dfy0dx0_5-textureblock],eax
  321.   mov ebx,xx
  322.   shl ebx,3
  323.   sub ebx,xx
  324.   neg ebx
  325.   add ebx,yx
  326.   shr ebx,16
  327.   mov al,bl
  328.   mov [edi-128+dfy0dx7-textureblock],eax
  329.   mov ebx,xy
  330.   shl ebx,19
  331.   sub eax,ebx
  332.   mov ebx,yy
  333.   shl ebx,16
  334.   add eax,ebx
  335.   mov al,byte ptr xx+2
  336.   mov [edi-128+dfy7dx0-textureblock],eax
  337.  
  338.   shl xx,3
  339.   shl xy,3
  340.   shl yx,3
  341.   shl yy,3
  342.  
  343.   cmp dir,0
  344.   jne @@vert
  345.  
  346. @@horz:
  347.   mov eax,xx
  348.   sub eax,yx
  349.   rol eax,16
  350.   mov retxi1,al
  351.   and eax,not 65535
  352.   mov retxf1,eax
  353.  
  354.   mov eax,xy
  355.   sub eax,yy
  356.   rol eax,16
  357.   mov retyi1,al
  358.   and eax,not 65535
  359.   mov retyf1,eax
  360.  
  361.   mov eax,scrwid
  362.   neg eax
  363.   inc eax
  364.   shl eax,3
  365.   mov retsp1,eax
  366.  
  367.   mov eax,xblocks
  368.   neg eax
  369.   imul xx
  370.   add eax,yx
  371.   rol eax,16
  372.   mov retxi2,al
  373.   and eax,not 65535
  374.   mov retxf2,eax
  375.  
  376.   mov eax,xblocks
  377.   neg eax
  378.   imul xy
  379.   add eax,yy
  380.   rol eax,16
  381.   mov retyi2,al
  382.   and eax,not 65535
  383.   mov retyf2,eax
  384.  
  385.   mov eax,xblocks
  386.   neg eax
  387.   add eax,scrwid
  388.   shl eax,3
  389.   mov retsp2,eax
  390.  
  391.   mov ebx,src
  392.   mov edi,dst
  393.  
  394.   mov edx,x0
  395.   rol edx,16
  396.   mov ecx,y0
  397.   rol ecx,16
  398.   xchg cl,dl
  399.  
  400.   mov eax,yblocks
  401.   mov c1,eax
  402. @@l1:
  403.     mov eax,xblocks
  404.     mov c2,eax
  405.   @@l2:
  406.       mov esi,8
  407.       call textureblock
  408.       add edx,retxf1
  409.       adc cl,retxi1
  410.       add ecx,retyf1
  411.       adc dl,retyi1
  412.       add edi,retsp1
  413.     dec c2
  414.     jnz @@l2
  415.  
  416.     add edx,retxf2
  417.     adc cl,retxi2
  418.     add ecx,retyf2
  419.     adc dl,retyi2
  420.     add edi,retsp2
  421.   dec c1
  422.   jnz @@l1
  423.   jmp @@done
  424.  
  425. @@vert:
  426.   mov eax,yblocks
  427.   neg eax
  428.   imul eax,yx
  429.   add eax,xx
  430.   rol eax,16
  431.   mov retxi1,al
  432.   and eax,not 65535
  433.   mov retxf1,eax
  434.  
  435.   mov eax,yblocks
  436.   neg eax
  437.   imul eax,yy
  438.   add eax,xy
  439.   rol eax,16
  440.   mov retyi1,al
  441.   and eax,not 65535
  442.   mov retyf1,eax
  443.  
  444.   mov eax,yblocks
  445.   neg eax
  446.   imul scrwid
  447.   inc eax
  448.   shl eax,3
  449.   mov retsp1,eax
  450.  
  451.   mov ebx,src
  452.   mov edi,dst
  453.  
  454.   mov edx,x0
  455.   rol edx,16
  456.   mov ecx,y0
  457.   rol ecx,16
  458.   xchg cl,dl
  459.  
  460.   mov eax,xblocks
  461.   mov c1,eax
  462. @@l3:
  463.     mov esi,yblocks
  464.     shl esi,3
  465.     call textureblock
  466.     add edx,retxf1
  467.     adc cl,retxi1
  468.     add ecx,retyf1
  469.     adc dl,retyi1
  470.     add edi,retsp1
  471.   dec c1
  472.   jnz @@l3
  473.  
  474. @@done:
  475.   ret
  476. endp
  477.  
  478. end
  479.